home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / capturing / simplevideoout / cvideooutput.cpp next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  11.6 KB  |  317 lines

  1. /*
  2.     File:        CVideoOutput.cpp
  3.     
  4.     Description: SimpleVideoOut is an example of using QuickTimes FireWire video
  5.                  output component to play a DV stream (.dv movie) out to a DV Camera.
  6.                  This code is based on VidOutApp originally written by Jay Lloyd, Casey King
  7.                  and Adrienne Wang.
  8.  
  9.     Author:        era
  10.  
  11.     Copyright:     © Copyright 2000 Apple Computer, Inc. All rights reserved.
  12.     
  13.     Disclaimer:    IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
  14.                 ("Apple") in consideration of your agreement to the following terms, and your
  15.                 use, installation, modification or redistribution of this Apple software
  16.                 constitutes acceptance of these terms.  If you do not agree with these terms,
  17.                 please do not use, install, modify or redistribute this Apple software.
  18.  
  19.                 In consideration of your agreement to abide by the following terms, and subject
  20.                 to these terms, Apple grants you a personal, non-exclusive license, under Apple’s
  21.                 copyrights in this original Apple software (the "Apple Software"), to use,
  22.                 reproduce, modify and redistribute the Apple Software, with or without
  23.                 modifications, in source and/or binary forms; provided that if you redistribute
  24.                 the Apple Software in its entirety and without modifications, you must retain
  25.                 this notice and the following text and disclaimers in all such redistributions of
  26.                 the Apple Software.  Neither the name, trademarks, service marks or logos of
  27.                 Apple Computer, Inc. may be used to endorse or promote products derived from the
  28.                 Apple Software without specific prior written permission from Apple.  Except as
  29.                 expressly stated in this notice, no other rights or licenses, express or implied,
  30.                 are granted by Apple herein, including but not limited to any patent rights that
  31.                 may be infringed by your derivative works or by other works in which the Apple
  32.                 Software may be incorporated.
  33.  
  34.                 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
  35.                 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
  36.                 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  37.                 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
  38.                 COMBINATION WITH YOUR PRODUCTS.
  39.  
  40.                 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
  41.                 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  42.                 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  43.                 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
  44.                 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
  45.                 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
  46.                 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  47.                 
  48.     Change History (most recent first): <1> 1/28/00 initial release
  49.  
  50. */
  51.  
  52. #include "CVideoOutput.h"
  53.  
  54. using namespace dts;
  55.  
  56. /*    The CVideoOutput Class is very easy to use and encapsulates the basic set of functions required
  57.     to output a DV Stream over FireWire.
  58.     
  59.     To instantiate a CVideoOutput object pass it your Movie.
  60. */
  61. CVideoOutput::CVideoOutput( const Movie inMovie ) : mMovie(NULL), mVOutputGWorld(NULL), mVOutputComponent(0), mVOutputInstance(NULL),
  62.                                                      mDefaultSoundOutComponent(NULL), mSoundOutComponent(NULL), mMovieClockInstance(NULL),
  63.                                                        mNumberAudioTracks(0), mVideoOutputInUse(false), rc(noErr)
  64. {
  65.     ComponentDescription    theVideoOutDesc;
  66.     
  67.     for ( UInt8 i = 0; i < kMaxAudioTrax; i++) {
  68.         mAudioMediaHandler[i] = NULL;
  69.     }
  70.     
  71.     if ( inMovie == NULL ) {
  72.         rc = paramErr;
  73.         return;
  74.     }
  75.     
  76.     mMovie = inMovie;
  77.     
  78.     // Find the first FireWire output component
  79.     theVideoOutDesc.componentType = QTVideoOutputComponentType;
  80.     theVideoOutDesc.componentSubType = kFireCodecType;
  81.     theVideoOutDesc.componentManufacturer = 0;
  82.     theVideoOutDesc.componentFlags = 0L;
  83.     theVideoOutDesc.componentFlagsMask = kQTVideoOutputDontDisplayToUser;
  84.     
  85.     mVOutputComponent = ::FindNextComponent( mVOutputComponent, &theVideoOutDesc );
  86.     if ( mVOutputComponent == 0 )
  87.         rc = badComponentType;
  88. }
  89.  
  90. /* Open( const unsigned char inClientNameStr[], const short inMode )
  91.         Opens the FireWire video output component, registers a client name with the component
  92.         and sets up the display mode. This method also acquires the audio media handlers for up to five
  93.         audio tracks for use later when setting up the sound device and will automatically close
  94.         a video output component if it's already open before re-instantiating a new one.
  95. */
  96. OSErr CVideoOutput::Open( const unsigned char inClientNameStr[], const short inMode )
  97. {
  98.     if ( mVOutputComponent == NULL || rc != noErr )
  99.         goto bail;
  100.         
  101.     // Close any open video out components
  102.     if ( mVOutputInstance != NULL) {
  103.         Close();
  104.     }
  105.     
  106.     mVOutputInstance = ::OpenComponent( mVOutputComponent );
  107.         
  108.     if ( mVOutputInstance == NULL ) {
  109.         rc = badComponentType;
  110.         goto bail;
  111.     }
  112.  
  113.     // Register your client name with the Video Output Component
  114.     ::QTVideoOutputSetClientName( mVOutputInstance, inClientNameStr );
  115.     
  116.     // Set the display mode
  117.     rc = ::QTVideoOutputSetDisplayMode( mVOutputInstance, inMode );
  118.     if ( rc ) {
  119.         Close();
  120.         goto bail;
  121.     } 
  122.     
  123.     // Find out how many tracks the movie contains,
  124.     // the for each track find out which contain a sound media type
  125.     // and finally grab the media handler for those tracks
  126.     long theTrackCount = ::GetMovieTrackCount( mMovie );
  127.     for ( UInt8 i = 1; i < theTrackCount + 1; i++) {
  128.         OSType aMediaType;
  129.         
  130.         Track aTrack = ::GetMovieIndTrack( mMovie, i );
  131.         Media aMedia = ::GetTrackMedia( aTrack );        
  132.         ::GetMediaHandlerDescription( aMedia, &aMediaType, NULL, NULL );    
  133.         
  134.         if ( aMediaType == SoundMediaType ) {
  135.             mAudioMediaHandler[mNumberAudioTracks] = ::GetMediaHandler( aMedia );
  136.             mNumberAudioTracks++;    
  137.         }
  138.     }
  139.     
  140. bail:
  141.     return rc;
  142. }
  143.  
  144. /* Close( void )
  145.         Closes the component instance and zeros the object. It is also called by the objects destructor.
  146. */
  147. void CVideoOutput::Close( void )
  148. {
  149.     if ( mVOutputInstance != NULL ) {
  150.         End();
  151.         ::CloseComponent( mVOutputInstance );
  152.     }
  153.     
  154.     mVOutputInstance = NULL;
  155.     mNumberAudioTracks = 0;    
  156.  
  157.     for ( UInt8 i = 0; i < kMaxAudioTrax; i++) {
  158.         mAudioMediaHandler[i] = NULL;
  159.     }
  160. }
  161.  
  162. /* Begin( Boolean inUseVOsdev = true, Boolean inUseVOClk = true )
  163.         Gains exclusive access to the hardware, sets up the sound output and the clock component
  164.         associated with the video output component. Begin also acquires the GWorld used by the video
  165.         output component. Both the sound and clock parameters are set to 'true' by default.
  166. */
  167. OSErr CVideoOutput::Begin( Boolean inUseVOsdev, Boolean inUseVOClk )
  168. {
  169.     if ( mVOutputInstance == NULL )
  170.         return paramErr;
  171.         
  172.     if ( mVideoOutputInUse ) {
  173.         rc = videoOutputInUseErr;
  174.         goto bail;
  175.     }
  176.  
  177.     // Get exclusive access to the video hardware
  178.     rc = ::QTVideoOutputBegin( mVOutputInstance );
  179.     if ( rc ) goto bail;
  180.     
  181.     mVideoOutputInUse = true;
  182.     
  183.     // Get the default sound out component
  184.     for ( UInt8 i = 0;i < mNumberAudioTracks; i++ ) {
  185.         rc = ::MediaGetSoundOutputComponent( mAudioMediaHandler[i], &mDefaultSoundOutComponent );
  186.         if ( rc ) goto bail;
  187.     }
  188.     
  189.     // Get the first sound output component associated with the video output component.
  190.     rc = ::QTVideoOutputGetIndSoundOutput( mVOutputInstance, 1, &mSoundOutComponent );
  191.     if ( rc == noErr ) {
  192.         ::SoundComponentSetInfo( (ComponentInstance)mSoundOutComponent, NULL, siSampleRate, (void *)eAudioRate44khz );
  193.     } else {
  194.         goto bail;
  195.     }
  196.     
  197.     // Get a pointer to the clock component associated with the video output component
  198.     // This is used to synchronize video and sound for a movie to the rate of the display
  199.     if ( inUseVOClk && ::ComponentFunctionImplemented( mVOutputInstance, kQTVideoOutputGetClockSelect ) ) {
  200.         rc = ::QTVideoOutputGetClock( mVOutputInstance, &mMovieClockInstance );
  201.         if ( rc ) goto bail;
  202.     }
  203.     
  204.     // Set up the sound device
  205.     SetSoundDevice( inUseVOsdev );
  206.     
  207.     // Get a pointer to the graphics world used by a video output component
  208.     rc = ::QTVideoOutputGetGWorld( mVOutputInstance, &mVOutputGWorld );
  209.     if ( rc ) goto bail;
  210.     
  211.     // Initially turn off the echo port
  212.     rc = SetEchoPort( NULL );
  213.  
  214. bail:    
  215.     return rc;
  216. }
  217.  
  218. /* End( void )
  219.         Relinquishes exclusive access to the hardware. Also called by Close().
  220. */
  221. void CVideoOutput::End( void )
  222. {
  223.     if ( mVideoOutputInUse ) {
  224.         // Because the video output component disposes of the instance of the clock component which was returned to us
  225.         // by the QTVideoOutputGetClock call in the Begin() method, we need to reset the clock for the movie to the default clock
  226.         // by calling SetMovieMasterClock with nil as the value of the clock component) before calling QTVideoOutputEnd()
  227.         ::SetMovieMasterClock( mMovie, (Component)NULL, NULL );
  228.         ::QTVideoOutputEnd( mVOutputInstance );
  229.         mVideoOutputInUse = false;
  230.     }
  231.     
  232.     // If the video output was in use, after the call to ::QTVideoOutputEnd() mVOutputGWorld is
  233.     // no longer valid as the the video output component automatically disposes of the
  234.     // graphics world. If you need to use the GWorld after calling End(), you can call
  235.     // CVideoOutput::GetGWorld() again but ONLY after the next time you call Begin() or it
  236.     // will return NULL.
  237.     // Egon's important safty tip - You must not call DisposeGWorld to dispose of the
  238.     // graphics world used by a video output component...that would be bad.
  239.     mVOutputGWorld = NULL;
  240.     
  241.     mDefaultSoundOutComponent = NULL;
  242.     mSoundOutComponent = NULL;
  243.     mMovieClockInstance = NULL;
  244. }
  245.  
  246. /* SetEchoPort( const CGrafPtr inEchoPort = NULL )
  247.         Allows you to display video both on an external video display and in a window.
  248.         Pass in a CGrafPtr to specify a window to display video sent to the device. When video
  249.         is displayed in the window you specify, the video is displayed in the window and sent
  250.         to the normal output of the video output device. SimpleVideoOut by default turns the
  251.         EchoPort on but allows you to turn it off.
  252. */
  253. OSErr CVideoOutput::SetEchoPort( const CGrafPtr inEchoPort )
  254. {
  255.     if ( mVOutputInstance == NULL )
  256.         return paramErr;
  257.         
  258.     if ( ::ComponentFunctionImplemented( mVOutputInstance, kQTVideoOutputSetEchoPortSelect ) ) {
  259.         if ( inEchoPort == NULL ) {
  260.             // Turn off Echo Port
  261.             rc = ::QTVideoOutputSetEchoPort( mVOutputInstance, (CGrafPtr)NULL );
  262.             if ( rc == noErr ) {
  263.                 if ( mVideoOutputInUse )
  264.                     ::SetMovieGWorld( mMovie, mVOutputGWorld, NULL );
  265.             }
  266.         } else {
  267.             // Set up Echo Port        
  268.             rc = ::QTVideoOutputSetEchoPort( mVOutputInstance, inEchoPort );
  269.             if ( rc == noErr ) {
  270.                 if ( mVideoOutputInUse )
  271.                     ::SetMovieGWorld( mMovie, inEchoPort, NULL);
  272.             }
  273.         }
  274.     } else {
  275.         rc = badComponentSelector;
  276.     }
  277.  
  278.     return rc;
  279. }
  280.  
  281. /* SetSoundDevice( const Boolean inUseVOsdev = true )
  282.         This call will turn on/off the use of the video output components sound device, by
  283.         default SimpleVideoOut turns it on. Passing in 'true' will set up the use of the
  284.         video output components sound device and also sets up the clock component which is used
  285.         to synchronize video and sound for a movie to the rate of the display. Passing in 'false'
  286.         will use the default sound device and default clock.
  287. */
  288. OSErr CVideoOutput::SetSoundDevice( Boolean inUseVOsdev )
  289. {
  290.     if ( mVOutputInstance == NULL )
  291.         return paramErr;
  292.     
  293.     if ( inUseVOsdev == true ) {
  294.         for ( UInt8 i = 0;i < mNumberAudioTracks; i++ ) {
  295.             rc = ::MediaSetSoundOutputComponent( mAudioMediaHandler[i], mSoundOutComponent );
  296.             if ( rc ) goto bail;
  297.         }
  298.     } else {    
  299.         for ( UInt8 i = 0;i < mNumberAudioTracks; i++ ) {
  300.             rc = ::MediaSetSoundOutputComponent( mAudioMediaHandler[i], mDefaultSoundOutComponent );
  301.             if( rc ) goto bail;
  302.         }
  303.     }
  304.     
  305.     // Setting the movie master clock to the video output clock needs to be called
  306.     // after setting up the sound or it's gets spanked back to the default clock
  307.     if ( mMovieClockInstance ) {
  308.         if ( inUseVOsdev == true ) {
  309.             ::SetMovieMasterClock( mMovie, (Component)mMovieClockInstance, NULL );
  310.         } else {
  311.             ::SetMovieMasterClock( mMovie, (Component)NULL, NULL );
  312.         }
  313.     }
  314.  
  315. bail:
  316.     return rc;
  317. }